var jamie = {
    // 	DEV_FLAG: true,
 	log: function(msg) {
 		if (jamie.DEV_FLAG) {
 			console.log(msg);
 		}
 	},
	api: {
		_ajaxCount: 0,
		call: function(method) {
			jamie.api._ajaxCount++;
			jamie.showSpinner();
			method();
		},
		createResponseHandler: function(resFn) {
			return function(res) {
				jamie.api._ajaxCount--;
				if (jamie.api._ajaxCount == 0) {
					jamie.hideSpinner();
				}
				resFn(res);
			};
		}
	},
	onStatusResponse: function(res) {
		if (res.authResponse) {
			// cache the userID
			jamie.setUid(res.authResponse.userID);
			jamie.drawLoggedIn();
		} else {
			jamie.drawLoggedOut();
		}
	},
	setUid: function(uid) {
		jamie._uid = uid;
	},
	getUid: function() {
		return jamie._uid;
	},
	login: function() {
		jamie.api.call(function() {
			FB.login(jamie.api.createResponseHandler(jamie.onStatusResponse),
				{scope:'user_checkins, friends_checkins, user_events, friends_events'});
		});
	},
	logout: function() {
		jamie.api.call(function() {	
			FB.logout(jamie.api.createResponseHandler(jamie.onStatusResponse));
		});
	},
	drawLoggedIn: function() {
		jamie.api.call(function() {
			FB.api('/me', jamie.api.createResponseHandler(function(res) {
				$('#logged-in-name').html(res.name);
				$('#logged-in-content').show();
				$('#logged-out-content').hide();
				
				jamie.getLocationAndFriendCheckins();
			}));
		});
	},
	drawLoggedOut: function() {
		$('#logged-out-content').show();
		$('#logged-in-content').hide();
	},
	getLocationAndFriendCheckins: function() {
		if (navigator && navigator.geolocation && navigator.geolocation.getCurrentPosition) {
			navigator.geolocation.getCurrentPosition(function(pos) {
				jamie.setCurrentPosition(pos);
			});
		} 
	},
	showCheckins: function() {
		var tabs = $('#tabs').find('a');
		for (var i = 0; i < tabs.length; i++) {
			var tab = $(tabs[i]);
			if (tab.hasClass('checkins')) {
				tab.addClass('selected');
			} else {
				tab.removeClass('selected');		
			}
		}
		$('#checkins-content').show();
		$('#events-content').hide();
		jamie.getFriendCheckins('checkins-main-content');
	},
	showEvents: function() {		
		var tabs = $('#tabs').find('a');
		for (var i = 0; i < tabs.length; i++) {
			var tab = $(tabs[i]);
			if (tab.hasClass('events')) {
				tab.addClass('selected');
			} else {
				tab.removeClass('selected');		
			}
		}
		$('#checkins-content').hide();
		$('#events-content').show();
		jamie.getFriendsEvents('events-main-content');
	},
	setCurrentPosition: function(pos) {
		jamie._currentPos = pos;
	},
	currentPosition: function() {
		return jamie._currentPos;
	},
	getFriendCheckins: function(loadingDivId, timestamp) {
		$('#' + loadingDivId).html('<img src="images/spinner.gif"/>Please be patient, loading data..');	
		if (testData && testData.checkins && jamie.DEV_FLAG) {
			jamie.onGetCheckinsResponse([
				eval(testData.checkins.query),
				eval(testData.checkins.friends), 
				eval(testData.checkins.pages)], loadingDivId);
		}
			var query = FB.Data.query(
			   'SELECT timestamp, message, author_uid, page_id, tagged_uids, coords FROM checkin WHERE \
				author_uid IN (SELECT uid2 FROM friend WHERE uid1 = {0}) ' 
				+ (timestamp ? 'AND timestamp < ' + timestamp : '') + '\
				order by timestamp \
				desc limit 10',
			 jamie.getUid());
		
		 // Now, construct two dependent queries - one each to get the
		 // names of the friends and the events referenced
		 var friends = FB.Data.query(
			   "select uid, name from user where uid in "
			 + "(select author_uid from {0})", query);
		 var pages = FB.Data.query(
			   "select page_id, name, location from page where page_id in "
			 + " (select page_id from {0})", query);
		
		 // Now, register a callback which will execute once all three
		 // queries return with data
		jamie.api.call(function() {	
			 FB.Data.waitOn([query, friends, pages], jamie.api.createResponseHandler(function(res) {
				jamie.onGetCheckinsResponse(res, loadingDivId);
			}));
		 });
		
	},
	
	json: {
		stringify: function(value) {
			var res = JSON.stringify(value);
			res = res.replace(/\\/g, "\\\\");
			res = res.replace(/'/g, "\\'");			
			return res;
		}
	},
	
	isWithinHundredMiles: function(coords) {
		var currPos = jamie.currentPosition();
		if (!currPos) return true;
		var p1 = new LatLon(currPos.coords.latitude, currPos.coords.longitude);                                                      
		var p2 = new LatLon(coords.latitude, coords.longitude);
		var dist = p1.distanceTo(p2);  // in km
		return dist <= 100 * 1.61; // convert miles to km
	},
	
	onGetCheckinsResponse: function(res, renderId) {
		var query = res[0];
		var friends = res[1];
		var pages = res[2];
		
		jamie.log(jamie.json.stringify(query));
		jamie.log(jamie.json.stringify(friends));
		jamie.log(jamie.json.stringify(pages));				
	
		
	   // build a map of page_id, uid to name
	   var pageDetails = {};
	   var friendNames = {};
	   FB.Array.forEach(pages, function(row) {
		 pageDetails[row['page_id']] = row;
	   });
	   FB.Array.forEach(friends, function(row) {
		 friendNames[row.uid] = row.name;
	   });

		var html = '';
		var timestamp = null;
		FB.Array.forEach(query, function(checkin) {
			// skip if not within 100 miles of here
			if (!jamie.isWithinHundredMiles(checkin.coords)) {
				jamie.log('purging friend checkin to ' + checkin['page_id'] 
					+ ' bc greater than 100 miles away');
				return;
			}
			var page = pageDetails[checkin['page_id']];			
			html+= '<div class="jevent">\
				<div><a target="_blank" href="http://facebook.com/' + checkin['page_id'] + '">' + page.name + '</a></div>';
			timestamp = checkin['timestamp'];
			html += '<div>' + jamie.getFormattedDate(timestamp*1000) + '</div>';			
			html += '<div>' + jamie.getLocationAndVenueText(page.location) + '</div>'
			html += '<div><a target="_blank" href="http://facebook.com/' + checkin['author_uid'] 
				+ '">' + friendNames[checkin['author_uid']] + '</a> checked in';
			var taggedUids = checkin['tagged_uids'];
			if (taggedUids.length > 0) {
				html += ' with ';
				html += jamie.getCommaSeparatedStringFromList(taggedUids, 
					'<a target="_blank" href="http://facebook.com/@@"><fb:name linked="false" uid="@@"></fb:name></a>');
			}	
			html += '</div>';			
			if (checkin['message']) {
				html+= '<div>"' + checkin['message'] + '"</div>';
			}
			html += '</div>'; 
				
		});		
		html += '<div id="load-more-checkins-' + timestamp 
			+ '"><a href="javascript:jamie.onLoadMoreCheckins(\'' 
			+ timestamp + '\')">Load more...</a></div>';
		$('#' + renderId).html(html);
		FB.XFBML.parse();
	},
	
	onLoadMoreCheckins: function(timestamp) {
		jamie.getFriendCheckins('load-more-checkins-' + timestamp, timestamp);
	},
	
	getFriendsEvents: function(loadingDivId, startTime) {
		$('#' + loadingDivId).html('<img src="images/spinner.gif"/>Please be patient, loading data..');	
		if (testData && testData.events && jamie.DEV_FLAG) {
			jamie.onGetEventsResponse([
				eval(testData.events.query), 
				eval(testData.events.friends), 
				eval(testData.events.events)], loadingDivId);
				return;
		}
		
		if (!jamie._rsvpTypes) jamie._rsvpTypes = {attending: true, unsure: true};
		var rsvpClause = '';
		for (key in jamie._rsvpTypes) {
			if (!jamie._rsvpTypes[key]) continue;
			if (!rsvpClause) {
				rsvpClause = 'AND (';
			} else {
				rsvpClause += ' OR ';
			}
			rsvpClause += "rsvp_status = '" + key + "'";
		}
		if (rsvpClause) rsvpClause += ')';
		if (!startTime) startTime = 'now()';
		 var query = FB.Data.query(
			   "SELECT eid, uid, rsvp_status,start_time from event_member WHERE uid \
			   in (select uid2 from friend where uid1 = {0}) " + rsvpClause + " \
			   AND start_time > " + startTime + " order by start_time limit 10",
			 jamie.getUid());
		
		 // Now, construct two dependent queries - one each to get the
		 // names of the friends and the events referenced
		 var friends = FB.Data.query(
			   "select uid, name from user where uid in "
			 + "(select uid from {0})", query);
		 var events = FB.Data.query(
			   "select eid, name, location, venue from event where eid in "
			 + " (select eid from {0})", query);
		
		 // Now, register a callback which will execute once all three
		 // queries return with data
		jamie.api.call(function() {	
			 FB.Data.waitOn([query, friends, events], jamie.api.createResponseHandler(function(res) {
				jamie.onGetEventsResponse(res, loadingDivId);
			}));
		 });
	},
	
	getFormattedDate: function(timeInMs) {
		var date = new Date(timeInMs);
		var dateFormatted = date.format('dddd, mmmm d, yyyy, h:MM TT');
		return dateFormatted;
	},
	
	onGetEventsResponse: function(res, renderId) {
		var query = res[0];
		var friends = res[1];
		var events = res[2];
		
		jamie.log(jamie.json.stringify(query));
		jamie.log(jamie.json.stringify(friends));
		jamie.log(jamie.json.stringify(events));		
			
	   // build a map of eid, uid to name
	   var eventDetails = {};
	   var friendNames = {};
	   FB.Array.forEach(events, function(row) {
		 eventDetails[row.eid] = row;
	   });
	   FB.Array.forEach(friends, function(row) {
		 friendNames[row.uid] = row.name;
	   });
	
	   // now display all the results
	   var html = '';
	   	var startTime = null;
	   FB.Array.forEach(query, function(row) {
		 var eventDetail = eventDetails[row.eid];
		 if (!eventDetail) {
		 	jamie.log('skipping event id ' + row.eid + ' bc didnt have event details');
		 	return;
		 }
		 if (eventDetail.venue && eventDetail.venue.latitude && eventDetail.venue.longitude 
		 	&& !jamie.isWithinHundredMiles(eventDetail.venue)) {
		 	jamie.log('skipping event id ' + row.eid + ' bc more than 100 miles away');
		 	return;
		 }
		 var rsvpStatus = row['rsvp_status'];
		 startTime = row['start_time'];
		 var dateFormatted = jamie.getFormattedDate(startTime*1000);		 
		 html += '<div class="jevent"><div class="jname"><a href="http://facebook.com/' + row.eid + '" target="_blank">'+ eventDetail.name + '</a></div>' 
		 	+ '<div class="jdate">' + dateFormatted + '</div>'
		 	+ '<div class="jlocation">' + jamie.getLocationAndVenueText(eventDetail.venue, eventDetail.location) + '</div>'
		 	+ '<div class="jfriends">'
		   + '<a target="_blank" href="http://facebook.com/' + row.uid + '">' + friendNames[row.uid] + '</a>'
		   + (rsvpStatus == 'attending' ?  ' is attending' : 
		   rsvpStatus == 'unsure' ?  ' is maybe attending' : 
		   rsvpStatus == 'not_replied' ? ' is invited' : ' is not going')			   
		   + '</div></div>';
	   });
	   html += '<div id="load-more-events-' + startTime + '"><a href="javascript:jamie.onLoadMoreEvents(\'' + startTime + '\')">Load more...</a></div>';
	   $('#' + renderId).html(html);
	 },
	 
	 onLoadMoreEvents: function(startTime) {
	 	jamie.getFriendsEvents('load-more-events-' + startTime, startTime);
	 },
	 
	 onSubmitEventRsvpTypes: function() {
	 	var checkboxes = $('#rsvpTypesCheckboxes').find('input[type="checkbox"]');
	 	FB.Array.forEach(checkboxes, function(box) {
	 		jamie._rsvpTypes[box.id] = box.checked;
	 	});
	 	jamie.getFriendsEvents('events-main-content');
	 	
	 },
	 
	 getLocationAndVenueText: function(venue, location) {
	 	var str = '';	 	
	 	if (location) str += (venue.id ? '<a target="_blank" href="http://facebook.com/' 
	 		+ venue.id + '">' : '') + location + (venue.id ? '</a>' : ''); 	 	
	 	if (venue.street) str += (str ? ', ' : '') + venue.street;
	 	if (venue.city) str += (str ? ', ' : '') + venue.city;	 	
	 	if (venue.state) str += (str ? ', ' : '') + venue.state;	 		 	
	 	if (venue.country) str += (str ? ', ' : '') + venue.country;	 		 		 	
	 	return str;
	 },
	
	getCommaSeparatedStringFromList: function(taggedUids, template) {
		var html = '';
		for (var j = 0; j < taggedUids.length; j++) {							
			html+= template.replace(/@@/g, taggedUids[j]);
			if (j != taggedUids.length - 1) {
				if (taggedUids.length != 2) {
					html+= ', ';
				} else {
					html += ' ';
				}
				if (j == taggedUids.length - 2) {
					html+= 'and '
				}
			}							
		}
		return html;
	},
	
	showSpinner: function() {
	// 	$('#spinner').show();
	},
	hideSpinner: function() {
		// $('#spinner').hide();
	}	
};